package com.maxjay.system.web.controller.struts;

import java.io.Serializable;
import java.io.UnsupportedEncodingException;
import java.net.URLDecoder;
import java.net.URLEncoder;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Map;
import java.util.Set;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.apache.commons.beanutils.PropertyUtils;
import org.apache.commons.lang.StringUtils;
import org.apache.log4j.Logger;
import org.apache.struts2.ServletActionContext;

import com.maxjay.common.exception.ERR;
import com.maxjay.common.exception.GeneException;
import com.maxjay.common.util.json.JsonParser;
import com.maxjay.system.bo.UserInfo;
import com.maxjay.system.constant.EncodeConstant;
import com.maxjay.system.core.Application;
import com.maxjay.system.core.cache.UserContextHolder;
import com.maxjay.system.core.interceptor.ViewState;
import com.maxjay.system.po.TSysUser;
import com.maxjay.system.service.UserService;
import com.opensymphony.xwork2.ActionSupport;
import com.opensymphony.xwork2.interceptor.annotations.After;
import com.opensymphony.xwork2.interceptor.annotations.Before;
import com.opensymphony.xwork2.interceptor.annotations.BeforeResult;

@SuppressWarnings("unchecked")
public class BaseController extends ActionSupport{
	
	/**
	 * 
	 */
	private static final long serialVersionUID = 1L;
	
	private static Logger logger = Logger.getLogger(BaseController.class);
	private static final String BACK_URL_MAP = "backUrlMap";
	
	/**
	 * 页面状态保持器
	 */
	protected ViewState viewState = new ViewState();
	
	protected Set<String> viewStateProperties = new HashSet<String>();

	protected HttpServletRequest request;
	protected HttpServletResponse response;
	
	/**
	 * 当前登录用户
	 */
	protected UserInfo currentUser;
	
	/**
	 * 当入口页面传递该参数时，参数的值形式为：encodeBackUrl=commonSimpleList.do%3FlistId=PROJECT%26%40query_char_project_code_eq%3DPM，
	 * 也可设置为encodeBackUrl=%{encodeCurrentUrl}
	 */
	protected String encodeBackUrl;
	protected String decodeBackUrl;
	protected String encodeCurrentUrl;
	protected String decodeCurrentUrl;
	
	/**
	 * 当页面存在翻页或者同一个页面需要多次提交时，
	 * 可以将页面内的元素设置成viewState类型的，
	 * 这样jsp页面即使没有该属性对应的元素，该属性的值仍可保持下来
	 */
	protected void configPropertiesInViewState(){
	}
	
	/**
	 * 将页面属性加入状态保持器中
	 * 
	 * @param properties
	 */
	protected void addPropertiesInViewState(String...properties){
		for(String property:properties){
			viewStateProperties.add(property);
		}
	}

	/**
	 * 使用struts的拦截器注解，在execute等方法之前调用此方法
	 */
	@Before
	public void beforeExecute(){
		this.request = ServletActionContext.getRequest();
		this.response = ServletActionContext.getResponse();
//		currentUser = (UserInfo) request.getSession().getAttribute(UserInfo.SYS_USERINFO);
		currentUser = UserContextHolder.getCurrentUser();
		this.configPropertiesInViewState();
		this.readViewState();
		this.resetCurrentAndBackUrl();
	}
	
	/**
	 * 设置当前页面和返回页面的URL
	 */
	private void resetCurrentAndBackUrl(){
		try {
			HttpServletRequest request = ServletActionContext.getRequest();
			decodeCurrentUrl = request.getRequestURI();
			String context = request.getContextPath();
			decodeCurrentUrl = decodeCurrentUrl.substring(context.length() + 1);
			if(StringUtils.isNotBlank(request.getQueryString())){
				decodeCurrentUrl = decodeCurrentUrl + "?" + request.getQueryString();
			}
			// 去除当前页面URL中的backUrl参数，该参数已存储在session的backUrlMap中，避免url过长
			if (decodeCurrentUrl.indexOf("&encodeBackUrl") != -1) {
				decodeCurrentUrl = decodeCurrentUrl.replaceAll("&encodeBackUrl=[^\\&]+", "");
			}
			encodeCurrentUrl = URLEncoder.encode(decodeCurrentUrl, EncodeConstant.UTF_8);
			dealDecodeCurrentUrl();
			if (StringUtils.isNotBlank(encodeBackUrl)) {
				Map<String, String> backUrlMap = (Map<String, String>) request.getSession().getAttribute("backUrlMap");
				if(backUrlMap == null){
					backUrlMap = new HashMap<String, String>();
				}
				decodeBackUrl = URLDecoder.decode(encodeBackUrl, EncodeConstant.UTF_8);
				backUrlMap.put(decodeCurrentUrl, decodeBackUrl);
				request.getSession().setAttribute(BACK_URL_MAP, backUrlMap);
			}
		} catch (UnsupportedEncodingException e) {
			e.printStackTrace();
			logger.error(e.getMessage(), e);
			throw GeneException.getGeneException(ERR.ERROR_ERR_MSG, e);
		}
	}
	
	/**
	 * 处理当前页面URL，由于decodeCurrentUrl会作为backUrlMap的key因此部分页面需特殊处理
	 * 
	 * @param currentPageUrl
	 * @return
	 */
	protected void dealDecodeCurrentUrl() {
	}

	/**
	 * 使用struts的拦截器注解，在execute等方法调用之后result返回之前调用此方法
	 */
	@BeforeResult
	public void beforeResult(){
		this.resetViewState();
	}
	
	/**
	 * 使用struts的拦截器注解，在execute等方法执行（且已返回result）之后调用此方法
	 * 	此时result已返回，对于action中属性值的修改将不会反应在页面上
	 */
	@After
	public void afterExecute(){
	}
	
	/**
	 * 读取viewState
	 * 
	 * @author:Administrator
	 */
	private void readViewState() {
		HttpServletRequest request = ServletActionContext.getRequest();
		String states = request.getParameter(ViewState.VIEWSTATE_KEY);
		if (StringUtils.isNotBlank(states)) {
			this.viewState = ViewState.parseViewState(states);
			request.setAttribute(ViewState.VIEWSTATE_KEY, this.viewState);
			for (String property : viewStateProperties) {
				Object value = this.viewState.getAttribute(property);
				if (value != null) {
					try {
						PropertyUtils.setProperty(this, property, value);
					} catch (Exception ex) {
						StringBuffer sb = new StringBuffer();
						sb.append("用视图状态初始化出错. 属性: ");
						sb.append(property);
						sb.append("类型: ");
						sb.append(value.getClass().toString());
						sb.append(value);
						String message = sb.toString();
						logger.error(message);
						throw GeneException.getGeneException(ERR.ERROR_ERR_MSG, message, ex);
					}
				}
			}
		}
	}
	
	/**
	 * 重置ViewState
	 * 
	 * @author:Administrator
	 */
	private void resetViewState() {
		for (String property : viewStateProperties) {
			try {
				Object value = PropertyUtils.getProperty(this, property);
				if (value != null) {
					if (value instanceof Serializable) {
						this.viewState.setAttribute(property, (Serializable) value);
					} else {
						StringBuffer sb = new StringBuffer();
						sb.append("属性[ ");
						sb.append(property);
						sb.append("]不能序列化，类型为[ ");
						sb.append(value.getClass().toString());
						sb.append("]，属性值为[");
						sb.append(value);
						sb.append("]");
						String message = sb.toString();
						logger.error(message);
						throw GeneException.getGeneException(ERR.ERROR_ERR_MSG, message);
					}
				}
			} catch (RuntimeException ex) {
				logger.error(ex.getMessage(), ex);
				throw ex;
			} catch (Exception ex) {
				logger.error(ex.getMessage(), ex);
				throw GeneException.getGeneException(ERR.ERROR_ERR_MSG, "设置视图状态出错:" + ex.getMessage(), ex);
			}
		}
	}
	
	protected void outputJsonStream(Object obj){
		try {
			//response.setContentType("application/text;charset=utf-8");
			response.setCharacterEncoding("UTF-8");
			if(obj instanceof String){
				response.getWriter().write((String)obj);
			} else {
				response.getWriter().write(JsonParser.convertObjectToJson(obj));
			}
		} catch (Exception e) {
			e.printStackTrace();
			logger.error(e.getMessage(), e);
			throw GeneException.getGeneException(ERR.ERROR_ERR_MSG, e);
		}
	}
	
	public ViewState getViewState() {
		return viewState;
	}

	public void setViewState(ViewState viewState) {
		this.viewState = viewState;
	}

	public String getEncodeBackUrl() {
		try {
			encodeBackUrl = URLEncoder.encode(encodeBackUrl, EncodeConstant.UTF_8);
		} catch (UnsupportedEncodingException e) {
			e.printStackTrace();
		}
		return encodeBackUrl;
	}

	public void setEncodeBackUrl(String encodeBackUrl) {
		this.encodeBackUrl = encodeBackUrl;
	}

	public String getEncodeCurrentUrl() {
		return encodeCurrentUrl;
	}

	public void setEncodeCurrentUrl(String encodeCurrentUrl) {
		this.encodeCurrentUrl = encodeCurrentUrl;
	}

	public void setDecodeBackUrl(String decodeBackUrl) {
		this.decodeBackUrl = decodeBackUrl;
	}

	public void setDecodeCurrentUrl(String decodeCurrentUrl) {
		this.decodeCurrentUrl = decodeCurrentUrl;
	}

	public String getDecodeCurrentUrl() {
		return decodeCurrentUrl;
	}
	
	/**
	 * 将当前页面的上一个页面路径解码，用于返回链接中
	 * 
	 * @return
	 */
	public String getDecodeBackUrl() {
		Map<String, String> backUrlMap = (Map<String, String>)ServletActionContext.getRequest().getSession().getAttribute(BACK_URL_MAP);
		String decodeBackUrl = backUrlMap.get(decodeCurrentUrl);
		return decodeBackUrl;
	}

	public UserInfo getCurrentUser() {
		return currentUser;
	}

	/**
	 * 设置session中的用户
	 * 
	 * @param currentSessionUser
	 */
	public void setCurrentSessionUser(UserInfo sessionUser) {
		this.currentUser = sessionUser;
//		request.getSession().setAttribute(UserInfo.SYS_USERINFO, sessionUser);
		UserContextHolder.setCurrentUser(sessionUser);
		// TODO: 加入SpringSecurity的用户信息更新代码
	}

	public void refreshCurrentSessionUser(TSysUser user){
		this.currentUser.refresh(user);
		UserService userService = (UserService) Application.getBeanContext().getBean("userService");
		this.setCurrentSessionUser(userService.initUserInfo(user));
	}
}